home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-31 | 4.4 KB | 259 lines | [TEXT/CWIE] |
- /*********************************************************************
- Project : GUSI - Grand Unified Socket Interface
- File : GUSIGlob.cp - Expand wildcard characters
- Author : Matthias Neeracher <neeri@iis.ethz.ch>
- Language : MPW C
-
- $Log: GUSIFile.cp,v $
- *********************************************************************/
-
- #include <ctype.h>
- #include <TextUtils.h>
-
- #include "GUSIFile_P.h"
- #include "TFileGlob.h"
-
- #pragma segment GUSI
-
- /* Slice up and count segments. To deal with aliases, "::"s actually
- count as an empty segment
- */
-
- static int SliceSegments(char * pattern)
- {
- int segments = 1;
-
- for (; *pattern; ++pattern)
- if (*pattern == ':') {
- *pattern = 0;
-
- if (pattern[1])
- ++segments;
- }
-
- return segments;
- }
-
- static Boolean HasWildCards(char * pattern)
- {
- for (;;) {
- switch (*pattern) {
- case '?':
- case '*':
- case '≈':
- return true;
- case '\\':
- case '∂':
- if (*++pattern)
- break;
- // Else fall through
- case 0:
- return false;
- default:
- break;
- }
- ++pattern;
- }
-
- return false;
- }
-
- TFileGlob::TFileGlob(const char * pattern, const TFileSpec * startDir)
- : TFileSpec(), patBuf(nil), track(nil)
- {
- if (!*pattern)
- error = bdNamErr;
- else if (*pattern != ':' && strchr(pattern, ':')) // full path pattern
- Root();
- else if (startDir)
- *(TFileSpec *)this = *startDir;
- else
- Default();
-
- if (*pattern == ':') {
- ++pattern;
-
- if (!*pattern) { // Very special case ":"
- segments = 0;
- valid = true;
-
- return;
- }
- }
-
- int patlen = strlen(pattern);
-
- if (!(valid = !error) || !(patBuf = new char[patlen+1]))
- return;
-
- memcpy(patBuf, pattern, patlen+1);
-
- UppercaseText(patBuf, patlen, smSystemScript);
-
- int segCount = SliceSegments(patBuf);
-
- if (segCount > 127) {
- error = bdNamErr;
-
- return;
- }
-
- if (!(track = new BackTrack[segCount]))
- return;
-
- segments = segCount;
- char * patSeg = patBuf;
-
- for (segCount = 0; segCount < segments; patSeg += strlen(patSeg)+1) {
- track[segCount].index = HasWildCards(patSeg) ? 0 : -1;
- track[segCount++].pattern = patSeg;
- }
-
- // Volume names always have to be matched exhaustively
-
- if (IsRoot())
- track[0].index = 0;
-
- valid = Next(track, segments, true);
- }
-
- Boolean TFileGlob::Next()
- {
- for (int depth = segments; depth--; )
- if (valid = Next(track+depth, segments - depth))
- return true;
-
- return valid = false;
- }
-
- static Boolean MatchName(const char * name, const char * pattern, int nameLen)
- {
- while (nameLen--) {
- switch (*pattern) {
- case '\\':
- case '∂':
- if (!*++pattern)
- --pattern; // special case at end of pattern
- // Fall through
- default:
- if (toupper(*name) != *pattern)
- return false;
- // Fall through
- case '?':
- ++name;
- ++pattern;
-
- break;
- case '*':
- case '≈':
- while (!MatchName(name, pattern+1, nameLen+1)) {
- if (nameLen-- < 0)
- return false; // "a", "*b"
- ++name; // "ba", "*a" or "ba", "*b"
- }
- return true; // "a", "*a"
- }
- }
-
- while (*pattern)
- switch (*pattern) {
- case '*':
- case '≈':
- ++pattern;
- break;
- default:
- return false;
- }
-
- return true;
- }
-
- Boolean TFileGlob::Next(BackTrack * track, int depth, Boolean init)
- {
- if (!depth) {
- if (!Exists())
- return false;
- Bless();
-
- return true;
- }
-
- if (track->index == -1) { // Exact match
- if (!init) // Won't match again
- return false;
- if (!*track->pattern)
- --*this;
- else
- *this += track->pattern;
-
- return Error() ? false : Next(track+1, depth - 1, true);
- }
-
- if (init) {
- *this += "";
-
- if (Error())
- return false;
-
- track->index = 0;
- track->vRefNum = vRefNum;
- track->parID = parID;
- }
-
- for (;;) {
- vRefNum = track->vRefNum;
- parID = track->parID;
-
- *(TFileSpec *)this = (*this)[++track->index];
-
- if (Error())
- break;
-
- static char uprName[64];
-
- memcpy(uprName, name+1, *name);
- UppercaseText(uprName, *name, smSystemScript);
-
- if (!MatchName((char *)name+1, track->pattern, *name))
- continue;
-
- if (Next(track+1, depth - 1, true))
- return true;
- }
-
- return false;
- }
-
- // C glue
-
- FileGlobRef NewFileGlob(const char * pattern)
- {
- FileGlobRef glob = new TFileGlob(pattern);
-
- if (!glob->Error())
- return glob;
-
- delete glob;
-
- return nil;
- }
-
- Boolean NextFileGlob(FileGlobRef glob)
- {
- return glob->Next();
- }
-
- Boolean FileGlob2FSSpec(FileGlobRef glob, FSSpec * spec)
- {
- if (glob->Valid())
- *spec = *(FSSpec *) glob;
-
- return glob->Valid();
- }
-
- void DisposeFileGlob(FileGlobRef glob)
- {
- delete glob;
- }
-
-